package cn.ulc.socket.weapp.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.ulc.common.constant.PubDataConstant;
import cn.ulc.common.constant.enums.AvailableStatus;
import cn.ulc.common.constant.enums.DeletedStatus;
import cn.ulc.common.exception.PlatformException;
import cn.ulc.common.model.param.PaginationParam;
import cn.ulc.common.util.CalendarUtil;
import cn.ulc.socket.weapp.common.BaseService;
import cn.ulc.socket.common.helper.MiniAppPayHelper;
import cn.ulc.socket.weapp.model.dto.OrderDTO;
import cn.ulc.socket.weapp.model.dto.OrderListDTO;
import cn.ulc.socket.weapp.model.dto.OrderPayDTO;
import cn.ulc.socket.weapp.model.dto.OrderResultDTO;
import cn.ulc.socket.weapp.model.param.OrderParam;
import cn.ulc.socket.weapp.model.param.OrderSaveParam;
import cn.ulc.socket.weapp.service.OrderServ;
import cn.ulc.store.dao.*;
import cn.ulc.store.dao.goods.GoodsDao;
import cn.ulc.store.dao.goods.GoodsSpecDao;
import cn.ulc.store.dao.goods.GoodsTypeDao;
import cn.ulc.store.dao.order.OrderDao;
import cn.ulc.store.dao.order.OrderItemDao;
import cn.ulc.store.dao.user.*;
import cn.ulc.store.entity.*;
import cn.ulc.store.entity.goods.Goods;
import cn.ulc.store.entity.goods.GoodsSpec;
import cn.ulc.store.entity.goods.GoodsType;
import cn.ulc.store.entity.order.Order;
import cn.ulc.store.entity.order.OrderItem;
import cn.ulc.store.entity.user.*;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.beetl.sql.core.engine.PageQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Service
@AllArgsConstructor
public class OrderServImpl extends BaseService implements OrderServ {

    OrderDao orderDao;
    OrderItemDao orderItemDao;
    SetInfoDao setInfoDao;
    DepositDao depositDao;
    GoodsSpecDao goodsSpecDao;
    MemberRechargeDao rechargeDao;
    MemberDao memberDao;
    CouponDao couponDao;
    UserCouponDao userCouponDao;
    PubDataDao pubDataDao;
    WeixinUserDao weixinUserDao;
    WxPayService wxPayService;
    BillDao billDao;
    GoodsDao goodsDao;
    GoodsTypeDao goodsTypeDao;
    ShopCartDao shopCartDao;
    private static final Log log = LogFactory.get();

    @Override
    @Transactional
    public OrderResultDTO createOrder(OrderSaveParam param) {
        WeixinUser loginUser = getCurrentUser();
        Company company = getCurrentCompany();
        if(param.getItemList().size()<=0) throw new PlatformException("无法获取商品列表!");
        UserCoupon coupon = param.getCoupon();
        Order order = new Order();
        setBaseInfo(order);
        order.setWxUserId(loginUser.getId());
        order.setMemberId(param.getMemberId());
        order.setCompanyId(company.getId());
        order.setOrderNo(generateCode(company.getId()));
        order.setGoodsAmount(param.getGoodsAmount());
        order.setPayAmount(param.getPayAmount());
        order.setCount(param.getCount());
        order.setGoodsRows(param.getRows());
        order.setStatus(PubDataConstant.ORDER_UNPAID);
        order.setRemark(param.getRemark());
        order.setFreightAmount(param.getFreightAmount());
        order.setDepositAmount(param.getDepositAmount());
        order.setReceiveType(PubDataConstant.RECEIVE_DELIVER);
        order.setReceiver(param.getReceiver());
        order.setReceivePhone(param.getReceivePhone());
        order.setReceiveAddress(param.getReceiveAddress());
        order.setIsCart(param.getIsCart());
        if(coupon!=null && coupon.getId()!=null) {
            order.setRemoveAmount(coupon.getAmount());
            order.setUserCouponId(coupon.getId());
            coupon.setIsUsed(true);
            setBaseInfo(coupon);
            userCouponDao.save(coupon);
        }
        orderDao.save(order);
        List<OrderItem> itemList = param.getItemList();
        SetInfo setInfo = setInfoDao.findByCondition(company.getId());
        List<Deposit> depositList = new ArrayList<>();
        for(OrderItem item:itemList){
            item.setId(null);
            setBaseInfo(item);
            item.setCompanyId(company.getId());
            item.setMemberId(param.getMemberId());
            item.setOrderId(order.getId());
            item.setMode(item.getType());
            BigDecimal amount = item.getNum().multiply(item.getGoodsPrice());
            if(order.getUserCouponId()!=null){
                UserCoupon userCoupon = userCouponDao.findOne(order.getUserCouponId());
                if(userCoupon!=null){
                    if(userCoupon.getUserScope().equals(PubDataConstant.COUPON_SCOPE_ALL)){
                        //全场通用代金券
                        amount = amount.subtract(amount.divide(order.getGoodsAmount()).multiply(order.getRemoveAmount()));
                    }else if(userCoupon.getUserScope().equals(PubDataConstant.COUPON_SCOPE_GOODS)){
                        //某一个商品的代金券
                        if(item.getGoodsId().intValue() == userCoupon.getGoodsId().intValue()){
                            amount = amount.subtract(amount.divide(order.getGoodsAmount()).multiply(order.getRemoveAmount()));
                        }
                    }else{
                        //某个分类的代金券
                        if(item.getGoodsTypeId().intValue() == userCoupon.getGoodsTypeId().intValue()){
                            amount = amount.subtract(amount.divide(order.getGoodsAmount()).multiply(order.getRemoveAmount()));
                        }
                    }
                }
            }
            item.setAmount(amount);
            if("DEPOSIT".equals(item.getType())){
                for(int i=0;i<item.getNum().intValue();i++){
                    Deposit deposit = new Deposit();
                    setBaseInfo(deposit);
                    deposit.setAmount(setInfo.getDepositAmount());
                    deposit.setOrderNo(order.getOrderNo());
                    deposit.setMemberId(param.getMemberId());
                    deposit.setWxUserId(loginUser.getId());
                    deposit.setStatus(PubDataConstant.DEPOSIT_UNPAID);
                    deposit.setCompanyId(company.getId());
                    depositList.add(deposit);
                }
            }
        }
        orderItemDao.saveAll(itemList);
        if(depositList.size()>0) depositDao.saveAll(depositList);
        return new OrderResultDTO(order.getOrderNo());
    }
    //生成唯一订单号
    public String generateCode(Long companyId) {
        Calendar cal = Calendar.getInstance();
        String month = (cal.get(Calendar.MONTH)+1)> 10 ? (cal.get(Calendar.MONTH)+1)+"" : "0" +(cal.get(Calendar.MONTH)+1);
        String date = cal.get(Calendar.DATE)> 10 ? cal.get(Calendar.DATE)+"" : "0" +cal.get(Calendar.DATE);
        String idStr = companyId.toString();
        if(idStr.length()<6){
            Integer len = 6-idStr.length();
            for(Integer i = 0;i<len;i++){
                idStr = "0"+idStr;
            }
        }
        String code = "T"+idStr+cal.get(Calendar.YEAR)+month+date;
        String maxOrderNo = orderDao.findMaxOrderNo(code);
        String orderNo = "0001";
        if (maxOrderNo != null) {
            orderNo = Integer.valueOf(maxOrderNo.substring(15))+1+"";
            Integer zeroLen = 4-orderNo.length();
            for(Integer i = 0;i<zeroLen;i++){
                orderNo = "0"+orderNo;
            }
        }
        return code+orderNo;
    }

    @Override
    public OrderPayDTO orderToPay(String ipAddress, OrderParam param) {
        String orderNo = param.getOrderNo();
        if (StrUtil.isBlank(orderNo)) throw new PlatformException("订单信息不能为空 ~");
        Order order = orderDao.findByOrderNo(orderNo);
        if (order == null) throw new PlatformException("订单信息获取失败，无法支付 ~");
        if (!order.getStatus().equals("UNPAID")) throw new PlatformException("订单状态需为  未支付状态 ~");


        WeixinUser weixinUser = getCurrentUser();
//        log.info("WeixinUser :" + weixinUser);
        if (StrUtil.isBlank(weixinUser.getOpenId())) throw new PlatformException("用户openId为空，支付失败 ~");

        WxPayUnifiedOrderRequest prepayInfo = MiniAppPayHelper.prepayInfo(orderNo,order.getPayAmount(), ipAddress, weixinUser.getOpenId());
//        WxPayService wxPayService = WxMiniAppHelper.getWxPayService();
        WxPayMpOrderResult payInfo = null;
        try {
            payInfo = wxPayService.createOrder(prepayInfo);
            String prepayId = payInfo.getPackageValue();
            prepayId = StringUtils.isNotBlank(prepayId) ? prepayId.substring(10) : "";
//            log.info("prepayId ==== :%s", prepayId);
            order.setPrepayId(prepayId);
            orderDao.save(order);
        } catch (WxPayException e) {
            e.printStackTrace();
        }
//        log.info("payInfo : %s", new Gson().toJson(payInfo));
        return new OrderPayDTO(payInfo);
    }

    @Override
    public String payCallBack(String xmlResult) {
        WxPayOrderNotifyResult result = null;
        log.info("===================WeixinPayCallback     xmlResult:%s", xmlResult);
        try {
//            WxPayService wxPayService = WxMiniAppHelper.getWxPayService();
            result = wxPayService.parseOrderNotifyResult(xmlResult);
            log.info("===================WeixinPayCallback     result:%s", result);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("解析回调异常");
            log.info("<xml><return_code><![CDATA[ERROR]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
//            throw new PlatformException("解析回调异常 ~ ");
            return  "解析回调异常 ~ ";
        }
        String result_code = result.getResultCode();
        if ("SUCCESS".equals(result_code)) {
            String out_trade_no = result.getOutTradeNo();
            log.info("=================订单号out_trade_no："+ out_trade_no);
            if (StringUtils.isBlank(out_trade_no)) {
                log.info("订单号为空");
//                throw new PlatformException("订单号为空");
                return  "订单号为空~ ";
//                renderText("<xml><return_code><![CDATA[ERROR]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
            }
            if(out_trade_no.indexOf("T")==0){
                Order order = orderDao.findByOrderNo(out_trade_no);
                //完善订单支付信息
               if(order.getStatus().equals(PubDataConstant.ORDER_UNPAID)) perfectOrder(order);
            }else if(out_trade_no.indexOf("M")==0){
                MemberRecharge memberRecharge = rechargeDao.findByOrderNo(out_trade_no);
                if(memberRecharge.getStatus().equals(PubDataConstant.ORDER_UNPAID))  perfectMemberRecharge(memberRecharge);
            }
        }
        return  "success";
    }

    //支付成功，完善订单支付状态
    @Transactional
    public void perfectOrder(Order order) {
        log.info("=================perfectOrder：");
        if (order.getStatus().equals(PubDataConstant.ORDER_UNPAID)) {
            order.setStatus(PubDataConstant.ORDER_PAID);
            order.setPaymentTime(new Date());
            orderDao.save(order);
        }
        List<Deposit> depositList = depositDao.findByOrderNo(order.getOrderNo());
        if(depositList.size()>0){
            for(Deposit deposit:depositList){
                deposit.setStatus(PubDataConstant.ORDER_PAID);
            }
            depositDao.saveAll(depositList);
        }
        List<OrderItem> itemList = orderItemDao.findListByOrderId(order.getId());
        BigDecimal amount = BigDecimal.ZERO;
        BigDecimal waterAmount = BigDecimal.ZERO;
        if(itemList.size()>0){
            List<GoodsSpec> goodsSpecList = new ArrayList<>();
            List<ShopCart> shopCartList = new ArrayList<>();
            for(OrderItem item:itemList){
                //改变商品库存
                GoodsSpec goodsSpec = goodsSpecDao.findById(item.getGoodsSpecId());
                goodsSpec.setStock(goodsSpec.getStock().subtract(item.getNum()));
                goodsSpecList.add(goodsSpec);
                if(item.getMode().equals("DEPOSIT")){
                    amount = amount.add(item.getAmount());
                }else {
                    waterAmount = waterAmount.add(item.getAmount());
                }
                //删除购物车
                if(order.getIsCart() == true){
                    ShopCart shopCart = shopCartDao.findByGoodsSpecId(order.getWxUserId(),item.getGoodsSpecId());
                    shopCart.setDeleted(DeletedStatus.DELETED);
                    setBaseInfo(shopCart);
                    shopCartList.add(shopCart);
                }
            }
            goodsSpecDao.saveAll(goodsSpecList);
            shopCartDao.saveAll(shopCartList);
        }
        //桶押金账单
        if(order.getDepositAmount().compareTo(BigDecimal.ZERO)> 0){
            String code = pubDataDao.findCodeByTypeAndName(PubDataConstant.DATA_TYPE_BILL,"桶押金");
            saveBill(order.getDepositAmount(),code,order.getOrderNo());
        }
        //运费
        if(order.getFreightAmount().compareTo(BigDecimal.ZERO)>0){
            String code = pubDataDao.findCodeByTypeAndName(PubDataConstant.DATA_TYPE_BILL,"配送费");
            saveBill(order.getFreightAmount(),code,order.getOrderNo());
        }
        //饮用水账单
        if(waterAmount.compareTo(BigDecimal.ZERO)>0){
            String code = pubDataDao.findCodeByTypeAndName(PubDataConstant.DATA_TYPE_BILL,"包装饮用水");
            saveBill(waterAmount,code,order.getOrderNo());
        }
        //百货账单
        if(amount.compareTo(BigDecimal.ZERO)>0){
            String code = pubDataDao.findCodeByTypeAndName(PubDataConstant.DATA_TYPE_BILL,"日用百货");
            saveBill(amount,code,order.getOrderNo());
        }

    }
    public Bill saveBill(BigDecimal amount,String code,String orderNo){
        if(StringUtils.isBlank(code)) return null;
        Bill bill = new Bill();
        bill.setDeleted(DeletedStatus.UN_DELETED);
        bill.setCreateAt(new Date());
        bill.setAmount(amount);
        bill.setBalance(bill.getBalance().add(amount));
        bill.setOrderNo(orderNo);
        bill.setEiType("+");
        bill.setBillType(code);
        bill.setDealDate(new Date());
        billDao.save(bill);
        return bill;
    }
    //支付成功，完善注册支付状态
    @Transactional
    public void perfectMemberRecharge(MemberRecharge recharge) {
        log.info("=================perfectMemberRecharge：");
        WeixinUser weixinUser = weixinUserDao.findOne(recharge.getWxUserId());
        if(weixinUser==null) throw new PlatformException("获取微信用户信息失败!");
        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.clear();

        Member member = null;
        if(recharge.getMemberId()!=null){
            member =  memberDao.findOne(recharge.getMemberId());
            if(member!=null){
                Date endTime =CalendarUtil.beginDate(member.getEndTime()) ;
                Date todayTime =CalendarUtil.beginDate(new Date()) ;
                int days = (int) ((todayTime.getTime() - endTime.getTime()) / (1000*3600*24));
                if(days > 0){
                    cal.setTime(date);//设置起时间
                }else{
                    cal.setTime(member.getEndTime());
                }
            }
        }
        if(member==null){
            member = new Member();
            member.setDeleted(DeletedStatus.UN_DELETED);
            member.setCreateAt(new Date());
            member.setName(weixinUser.getRealName());
            member.setSex(weixinUser.getSex());
            member.setPhone(weixinUser.getPhone());
            member.setBirthday(weixinUser.getBirthDay());
            member.setCompanyId(weixinUser.getCompanyId());
            member.setWxUserId(weixinUser.getId());
            member.setStartTime(date);
            cal.setTime(date);//设置起时间

        }
        cal.add(Calendar.YEAR,1);
        member.setEndTime(cal.getTime());
        member.setStatus(AvailableStatus.AVAILABLE);
        memberDao.save(member);

        if (recharge.getStatus().equals(PubDataConstant.ORDER_UNPAID)) {
            recharge.setMemberId(member.getId());
            recharge.setStatus(PubDataConstant.ORDER_PAID);
            recharge.setModifyAt(new Date());
            rechargeDao.save(recharge);
        }
        String code = pubDataDao.findCodeByTypeAndName(PubDataConstant.DATA_TYPE_COUPON,"会员礼包");
        Coupon coupon = couponDao.findByType(member.getCompanyId(),code);
        if(coupon!=null) {
            cal.clear();
            cal.setTime(date);//设置起时间
            for(int i = 1;i<=12;i++){
                UserCoupon userCoupon = new UserCoupon();
                userCoupon.setDeleted(DeletedStatus.UN_DELETED);
                userCoupon.setCouponId(coupon.getId());
                userCoupon.setIsFull(coupon.getIsFull());
                userCoupon.setFullAmount(coupon.getFullAmount());
                userCoupon.setUserScope(coupon.getUserScope());
                userCoupon.setGoodsId(coupon.getGoodsId());
                userCoupon.setGoodsTypeId(coupon.getGoodsTypeId());
                userCoupon.setAmount(coupon.getAmount());
                userCoupon.setIsUsed(false);
                String newCode = "C"+PubDataConstant.DATA_TYPE_COUPON+member.getWxUserId();
                String maxCode = userCouponDao.findMaxCode(member.getWxUserId(),newCode);
                Integer len = 13 - newCode.length();
                String num = "1";
                if(StringUtils.isNotBlank(maxCode)){
                    num =  (Integer.valueOf(maxCode.substring(newCode.length()))+1)+"";
                }
                len = len - num.length();
                for(int j = 0;j<len;j++){
                    newCode+="0";
                }
                userCoupon.setCode(newCode+num);
                userCoupon.setCompanyId(member.getCompanyId());
                userCoupon.setCouponId(coupon.getId());
                userCoupon.setMemberId(member.getId());
                userCoupon.setStatus(PubDataConstant.COUPON_STATUS_NOT_START);
                userCoupon.setTitle(coupon.getTitle());
                userCoupon.setWxUserId(member.getWxUserId());
                userCoupon.setBeginTime(cal.getTime());
                userCoupon.setIsForever(true);
                cal.add(Calendar.MONTH, 1);
                userCoupon.setRemark(coupon.getRemark());
                userCouponDao.save(userCoupon);
            }
        }

    }

    @Override
    public OrderListDTO findListPage(String status, PaginationParam param) {
        WeixinUser loginUser = getCurrentUser();
        Company company = getCurrentCompany();
        Map<String,Object> condition = new HashMap<>();
        condition.put("wxUserId",loginUser.getId());
        condition.put("companyId",company.getId());
        if(!"ALL".equals(status)) condition.put("status",status);
        PageQuery pageQuery = initPageQuery(param);
        pageQuery.setParas(condition);
        orderDao.findListPage(pageQuery);
        return new OrderListDTO(pageQuery.getList(),pageQuery.getTotalRow());
    }
    @Override
    public OrderDTO findDetail(String orderNo) {
        Order order = orderDao.findByOrderNo(orderNo);
        if (order == null) throw new PlatformException("获取订单信息失败!");
        List<OrderItem> itemList = orderItemDao.findListByOrderId(order.getId());
        order.setOrderItem(itemList);
        return new OrderDTO(order);
    }

    @Override
    @Transactional
    public Boolean cancelOrder(Long id) {
        Order order = orderDao.findOne(id);
        if (order == null) throw new PlatformException("获取订单信息失败!");
        setBaseInfo(order);
        order.setStatus(PubDataConstant.ORDER_CANCEL);
//        order.setDeleted(DeletedStatus.DELETED);
        if(order.getUserCouponId()!=null){
            UserCoupon userCoupon = userCouponDao.findOne(order.getUserCouponId());
            if(userCoupon!=null) {
                userCoupon.setIsUsed(false);
                setBaseInfo(userCoupon);
                userCouponDao.save(userCoupon);
            }
        }
        orderDao.save(order);
        return true;
    }

    @Override
    public void executeJob() {
//        Company company = getCurrentCompany();
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.setTime(new Date());
        cal.add(Calendar.MINUTE, -15);// 5分钟之前的时间
        String date = CalendarUtil.dateToString(cal.getTime(),CalendarUtil.SDF_DEFAULT_FULL);
        List<Order> orderList = orderDao.findByDate(PubDataConstant.ORDER_UNPAID,date);
        if(orderList!=null && orderList.size()>0){
            List<UserCoupon> couponList = new ArrayList<>();
            List<Order> orders = new ArrayList<>();
            for(Order order:orderList){
                order.setStatus(PubDataConstant.ORDER_CANCEL);
                orders.add(order);
                if(order.getUserCouponId()!=null){
                    UserCoupon userCoupon = userCouponDao.findOne(order.getUserCouponId());
                    if(userCoupon!=null) {
                        userCoupon.setIsUsed(false);
                        setBaseInfo(userCoupon);
                        couponList.add(userCoupon);
                    }
                }
            }
            orderDao.saveAll(orders);
            userCouponDao.saveAll(couponList);
        }
    }
}
